use encoding::utf8;
use strings;

// A token with no additional context, such as '+'
export type btoken = enum {
	// Keep ordered with bmap
	// Alpha sorted
	ATTR_FINI,
	ATTR_INIT,
	ATTR_NORETURN,
	ATTR_OFFSET,
	ATTR_SYMBOL,
	ATTR_TEST,
	UNDERSCORE,
	ABORT,
	ALLOC,
	APPEND,
	AS,
	ASSERT,
	BOOL,
	BREAK,
	CHAR,
	CONST,
	CONTINUE,
	DEF,
	DEFER,
	DELETE,
	ELSE,
	ENUM,
	EXPORT,
	F32,
	F64,
	FALSE,
	FN,
	FOR,
	FREE,
	I16,
	I32,
	I64,
	I8,
	IF,
	INT,
	IS,
	LEN,
	LET,
	MATCH,
	NULL,
	NULLABLE,
	OFFSET,
	RETURN,
	RUNE,
	SIZE,
	STATIC,
	STR,
	STRUCT,
	SWITCH,
	TRUE,
	TYPE,
	U16,
	U32,
	U64,
	U8,
	UINT,
	UINTPTR,
	UNION,
	USE,
	VOID,
	LAST_KEYWORD = VOID,

	// Operators
	ANDEQ,
	BAND,
	BNOT,
	BOR,
	BXOR,
	BXOREQ,
	CASE,
	COLON,
	COMMA,
	DIV,
	DIVEQ,
	DOT,
	DOUBLE_COLON,
	ELLIPSIS,
	EQUAL,
	GREATER,
	GREATEREQ,
	LAND,
	LBRACE,
	LBRACKET,
	LEQUAL,
	LESS,
	LESSEQ,
	LNOT,
	LOR,
	LPAREN,
	LSHIFT,
	LSHIFTEQ,
	LXOR,
	MINUS,
	MINUSEQ,
	MINUSMINUS,
	MODEQ,
	MODULO,
	NEQUAL,
	OREQ,
	PLUS,
	PLUSEQ,
	PLUSPLUS,
	QUESTION,
	RBRACE,
	RBRACKET,
	RPAREN,
	RSHIFT,
	RSHIFTEQ,
	SEMICOLON,
	SLICE,
	TIMES,
	TIMESEQ,
};

const bmap: [_]str = [
	// Keep ordered with btoken
	"@fini",
	"@init",
	"@noreturn",
	"@offset",
	"@symbol",
	"@test",
	"_",
	"abort",
	"alloc",
	"append",
	"as",
	"assert",
	"bool",
	"break",
	"char",
	"const",
	"continue",
	"def",
	"defer",
	"delete",
	"else",
	"enum",
	"export",
	"f32",
	"f64",
	"false",
	"fn",
	"for",
	"free",
	"i16",
	"i32",
	"i64",
	"i8",
	"if",
	"int",
	"is",
	"len",
	"let",
	"match",
	"null",
	"nullable",
	"offset",
	"return",
	"rune",
	"size",
	"static",
	"str",
	"struct",
	"switch",
	"true",
	"type",
	"u16",
	"u32",
	"u64",
	"u8",
	"uint",
	"uintptr",
	"union",
	"use",
	"void",
	"&=",
	"&",
	"^",
	"^=",
	"~",
	"|",
	"=>",
	":",
	",",
	"/",
	"/=",
	".",
	"::",
	"...",
	"=",
	">",
	">=",
	"&&",
	"{",
	"[",
	"==",
	"<",
	"<=",
	"!",
	"||",
	"(",
	"<<",
	"<<=",
	"^^",
	"-",
	"-=",
	"--",
	"?",
	"%=",
	"%",
	"!=",
	"|=",
	"+",
	"+=",
	"++",
	"}",
	"]",
	")",
	">>",
	">>=",
	";",
	"..",
	"*",
	"*=",
];

// A loop label, such as ':example'
export type label = str;

// A name, such as 'example'
export type name = str;

export type iconst = i64;
export type fconst = f64;

// A token for a literal value, such as '1337u32'
export type literal = (u8 | u16 | u32 | u64 | uint | uintptr | i8 | i16 | i32 |
	i64 | int | iconst | f32 | f64 | fconst | rune | str);

// A location within a source file.
// The path is borrowed from the file name given to the lexer.
export type location = struct {
	path: str,
	line: uint,
	col: uint
};

// A single lexical token.
export type token = (btoken | label | name | literal);

// Converts a token to its string representation
export fn tokstr(tok: token) const str = match (tok) {
	b: btoken => bmap[b: int],
	n: name => n: str,
	l: literal => match (l) {
		u8 => "u8",
		u16 => "u16",
		u32 => "u32",
		u64 => "u64",
		uint => "uint",
		uintptr => "uintptr",
		i8 => "i8",
		i16 => "i16",
		i32 => "i32",
		i64 => "i64",
		int => "int",
		iconst => "iconst",
		f32 => "f32",
		f64 => "f64",
		fconst => "fconst",
		rune => "rune",
		str => "str",
	},
	* => abort(), // TODO
};
